package com.yjsn.base.handler;

import com.alibaba.fastjson2.JSON;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonMappingException.Reference;
import com.yjsn.base.domain.AjaxResult;
import com.yjsn.base.exception.*;
import com.yjsn.commom.HttpStatus;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.multipart.support.MissingServletRequestPartException;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @comment 全局异常捕捉
 * @Author Liu Yang 2025/4/30 11:16
 */
@ControllerAdvice
public class GlobalExceptionHandler {
    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 全局未捕捉的异常
     *
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public AjaxResult exceptionHandler(HttpServletRequest req, Exception e) {
        String message = e.getMessage();
        message = StringUtils.isBlank(message) ? "no message." : message;
        logger.error("exceptionHandler:未捕捉的异常：{}: {}", req.getRequestURL(), message, e);
        //return JsonResult.getInnerFail(JsonResult.ERROR_SYS.getCode(), message);
        return AjaxResult.error(HttpStatus.ERROR, "系统错误，请稍后重试！");
    }

    /**
     * 未登陆
     */
    @ExceptionHandler(NotLoginException.class)
    @ResponseBody
    public AjaxResult NotLoginException(NotLoginException e, HttpServletRequest request)
    {
        String requestURI = request.getRequestURI();
        logger.error("请求地址'{}'，'{}': 用户未登陆", requestURI, request.getMethod());
        return AjaxResult.error(HttpStatus.FORBIDDEN, e.getMessage());
    }

    /**
     * 非会员异常
     */
    @ExceptionHandler(NotMemberException.class)
    @ResponseBody
    public AjaxResult NotMemberException(NotMemberException e, HttpServletRequest request)
    {
        String requestURI = request.getRequestURI();
        logger.error("请求地址'{}'，'{}': 非会员用户请求", requestURI, request.getMethod());
        return AjaxResult.error(HttpStatus.UNAUTHORIZED, e.getMessage());
    }

    /**
     * 签名
     */
    @ExceptionHandler(SignException.class)
    @ResponseBody
    public AjaxResult SignException(SignException e, HttpServletRequest request)
    {
        String requestURI = request.getRequestURI();
        logger.error("请求地址'{}'，'{}': 签名错误", requestURI, request.getMethod());
        return AjaxResult.error(HttpStatus.ERROR, e.getMessage());
    }
    /**
     * 通用服务异常
     */
    @ExceptionHandler(ServiceException.class)
    @ResponseBody
    public AjaxResult ServiceException(ServiceException e, HttpServletRequest request)
    {
        String requestURI = request.getRequestURI();
        logger.error("请求地址'{}'，'{}': 服务异常", requestURI, request.getMethod());
        return AjaxResult.error(HttpStatus.ERROR, e.getMessage());
    }


    /**
     * 数据转换异常
     *
     */
    @ExceptionHandler(value = ClassCastException.class)
    @ResponseBody
    public AjaxResult classCastException(ClassCastException e) {
        logger.error("数据转换异常:{}", e.getMessage(), e);
        return AjaxResult.error(HttpStatus.ERROR, "数据转换异常" );
    }
    /**
     * 请求参数类型转换异常
     *
     */
    @ExceptionHandler(value = MethodArgumentTypeMismatchException.class)
    @ResponseBody
    public AjaxResult mismatchExceptionHandler(MethodArgumentTypeMismatchException e) {
        logger.error("参数转换失败:{}, {}:{}, {}", Objects.requireNonNull(e.getParameter().getMethod()).getName(),
                e.getName(), e.getValue(), e.getMessage());
        return AjaxResult.error("9001", "非法的参数类型" );
    }

    /**
     * 请求参数类型转换异常
     *
     */
    @ExceptionHandler(value = JsonMappingException.class)
    @ResponseBody
    public AjaxResult jsonMappingExceptionHandler(JsonMappingException e) {
        logger.error("参数转换失败:{}, {}:{}, {}", e.getPathReference());
        return AjaxResult.error(HttpStatus.ERROR,
                "非法的参数");
    }

    @ExceptionHandler(value = HttpMessageNotReadableException.class)
    @ResponseBody
    public AjaxResult mismatchExceptionHandler(HttpServletRequest req, HttpMessageNotReadableException e) {
        Throwable cause = e.getCause();
        if (cause != null) {
            if (cause instanceof JsonMappingException) {
                JsonMappingException jme = (JsonMappingException) cause;
                String params = jme.getPath().stream().map(Reference::getFieldName).collect(Collectors.joining(","));
                logger.error("参数转换失败:{}, {}:{}, {}", params, jme.getMessage());
                return AjaxResult.error(HttpStatus.ERROR,
                        "非法的参数: " + params);
            }
        }
        return exceptionHandler(req, e);
    }

    /**
     * 请求方式不正确
     *
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    @ResponseBody
    public AjaxResult methodNotSupportedHandler(HttpRequestMethodNotSupportedException e, HttpServletRequest request) {
        logger.error("url[{}]:{} -> 请求方式不正确:{}", request.getMethod(), request.getRequestURL(), e.getMessage());
        return AjaxResult.error(HttpStatus.ERROR, "请求方式不正确");
    }

    /**
     * 缺失参数
     *
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    @ResponseBody
    public AjaxResult missingParameterHandler(MissingServletRequestParameterException e, HttpServletRequest request) {
        logger.error("url:{} -> 缺失参数:{}", request == null ? null : request.getRequestURL(), e.getMessage());
        return AjaxResult.error(HttpStatus.ERROR, "缺失参数: " + e.getParameterType() + " " + e.getParameterName());
    }

    /**
     * 缺失参数
     *
     * @author LiuYang
     */
    @ExceptionHandler(MissingServletRequestPartException.class)
    @ResponseBody
    public AjaxResult missingPartHandler(MissingServletRequestPartException e, HttpServletRequest request) {
        logger.error("url:{} -> 缺失参数:{}", request == null ? null : request.getRequestURL(), e.getMessage());
        return AjaxResult.error(HttpStatus.ERROR, "缺失参数: " + e.getRequestPartName());
    }

    /**
     * 参数效验异常
     *
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public AjaxResult missingParameterHandler(MethodArgumentNotValidException e, HttpServletRequest request) {
        logger.error("url:{} -> 参数效验异常:{}", request == null ? null : request.getRequestURL(), e.getMessage());
        // 获取异常信息
        BindingResult exceptions = e.getBindingResult();
        // 判断异常中是否有错误信息，如果存在就使用异常中的消息，否则使用默认消息
        if (exceptions.hasErrors()) {
            List<ObjectError> errors = exceptions.getAllErrors();
            if (!errors.isEmpty()) {
                // 这里列出了全部错误参数，按正常逻辑，只需要第一条错误即可
                String errorsStr = errors.stream().map(DefaultMessageSourceResolvable::getDefaultMessage)
                        .collect(Collectors.joining(","));
                if (errorsStr.contains("用户Token不能为空")) {
                    return AjaxResult.error(HttpStatus.UNAUTHORIZED,"用户未授权");
                }
                return AjaxResult.error(HttpStatus.ERROR, errorsStr);
            }
        }
        return AjaxResult.error(HttpStatus.ERROR, e.getMessage());
    }

    @ExceptionHandler(BindException.class)
    @ResponseBody
    public AjaxResult beanPropertyBindingResult(BindException e, HttpServletRequest request) {
        logger.error("url:{} -> BindException异常:{}", request == null ? null : request.getRequestURL(), e.getMessage(), e);
        // 获取异常信息
        BindingResult exceptions = e.getBindingResult();
        // 判断异常中是否有错误信息，如果存在就使用异常中的消息，否则使用默认消息
        if (exceptions.hasErrors()) {
            List<ObjectError> errors = exceptions.getAllErrors();
            if (!errors.isEmpty()) {
                // 这里列出了全部错误参数，按正常逻辑，只需要第一条错误即可
                return AjaxResult.error("9007", errors.stream()
                        .map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining(",")));
            }
        }
        return AjaxResult.error("9007", e.getMessage());
    }

    /**
     * 第三方接口请求异常
     *
     */
    @ExceptionHandler(RestThirdException.class)
    @ResponseBody
    public AjaxResult httpClientErrorHandler(RestThirdException e) {
        String bodyMsg = e.getBody() != null ? (" body:" + JSON.toJSONString(e.getBody())) : "";
        String headerMsg = e.getHttpHeaders() != null ? (" headers:" + JSON.toJSONString(e.getHttpHeaders())) : "";
        logger.error("Rest Third ERROR, {}:{}{}{} -> {}", e.getMethod(), e.getUrl(), bodyMsg, headerMsg, e.getMessage());
        return AjaxResult.error(HttpStatus.ERROR, e.getMessage());

    }

    /**
     * 工具类异常
     *
     */
    @ExceptionHandler(UtilException.class)
    @ResponseBody
    public AjaxResult httpClientErrorHandler(UtilException e) {
        logger.error("UtilException ERROR, {}",  e.getMessage());
        return AjaxResult.error(HttpStatus.ERROR, e.getMessage());
    }


}
